home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Copyright (c) 1990,1991 Keld Simonsen
- ** All rights reserved.
- **
- ** Written by Keld Simonsen, RAP, Sct. Joergens Alle 8,
- ** DK-1615 Copenhagen V, Denmark
- **
- ** Redistribution and use of this routine in source and binary forms are
- ** permitted provided that: (1) source distributions retain this entire
- ** copyright notice. (2) The character and character set codes and names
- ** may not be changed. (3) The programming code must remain backwards
- ** compatible.
- **
- ** The restriction on altering of names is done so that all versons
- ** of the code have a chance of being compatible. If you want alterations
- ** or additions, please mail me (preferably email to keld@dkuug.dk)
- ** and I will consider it for future releases.
- **
- ** If the material is included in commercial products, donations
- ** will be most appreciated.
- **
- ** Keld Simonsen
- **
- ** Code revised for better sendmail operation by Paul Pomes, University of
- ** Illinois.
- */
-
- #include "sendmail.h"
-
- #ifdef BIT8
- # ifndef lint
- static char RcsId[] = "@(#)$Header: /usr/local/src/mail/sendmail/ida/charset/RCS/strcnv.c,v 2.2 1991/06/28 18:05:36 paul Exp $";
- # endif /* !lint */
-
- # ifndef MAPDIR
- define MAPDIR "/usr/local/lib/mail/char"
- # endif /* !MAPDIR */
-
- static char mapdir[] = MAPDIR;
- static char fmnem[] = "MNEM";
- static IN_CH *chset = NULL;
- static CHARSET *charsets = NULL;
-
- # ifdef __STDC__
- static int findc(unsigned int);
- static INT16S * getinch(const char *);
- static CHAR8U * getoutch(const char *);
- # ifdef CC_WONT_PROMOTE
- static char upper(char);
- # else /* !CC_WONT_PROMOTE */
- static char upper(int);
- # endif /* CC_WONT_PROMOTE */
- # else /* !__STDC__ */
- static int findc();
- static INT16S * getinch();
- static CHAR8U * getoutch();
- static char upper();
- # endif /* __STDC__ */
- static int getchbas();
-
- /*
- ** strcnv -- convert a string from one character set to another.
- **
- ** Parameters:
- ** r_chset -- the character set to convert to.
- ** s_chset -- the character set to convert from.
- ** result -- the converted character string.
- ** source -- the character string to convert.
- **
- ** Returns:
- ** pointer to result
- **
- ** Side Effects:
- ** none.
- */
-
- #define r_out r_chset->out
- #define s_in s_chset->in
- #define r_esc r_chset->esc
- #define s_esc s_chset->esc
-
- CHAR8U *
- strcnv(r_chset, s_chset, result, source)
- register CHARSET *r_chset, *s_chset;
- register CHAR8U *result, *source;
- {
- CHAR8U *save = result;
- register int o, c; /* intermediate binary value */
- register INT16S mnem;
-
- while (c = *source++)
- {
- /* printf(" %c %c %c",c,*source,s_esc); */
- if (c == s_esc)
- {
- /* Two esc in a row -> one escape
- *
- * If esc followed by defined mnemonic, next char is
- * mnemonic.
- */
-
- if (*source == s_esc)
- {
- o = *(s_in + s_esc);
- source++;
- }
- else
- {
- o = findc(*source * C256 + *(source + 1));
- source += 2;
- }
- }
- else
- o = *(s_in + c);
- if (!o)
- o = 64; /* if not defined in input: underline */
-
- /* printf(" %d %d %c",o,r_esc,r_esc); */
- if (*(r_out + o) == r_esc)
- {
- *result++ = r_esc;
- *result++ = r_esc;
- }
- else if (*(r_out + o))
- *result++ = *(r_out + o);
- else
- {
- mnem = *(chset + o);
- *result++ = r_esc;
- *result++ = *(r_out + *(s_in + (mnem / C256)));
- *result++ = *(r_out + *(s_in + (mnem % C256)));
- }
- }
- *result++ = '\0';
- return (save);
- }
- /*
- ** strncnv -- convert a string from one character set to another.
- **
- ** Parameters:
- ** r_chset -- the character set to convert to.
- ** s_chset -- the character set to convert from.
- ** result -- the converted character string.
- ** source -- the character string to convert.
- ** n -- number of characters to convert
- **
- ** Returns:
- ** pointer to result
- **
- ** Side Effects:
- ** none.
- */
-
- CHAR8U *
- strncnv(r_chset, s_chset, result, source, n)
- register CHARSET *r_chset, *s_chset;
- CHAR8U *result, *source;
- int n;
- {
- CHAR8U c, *save = result;
- int o; /* intermediate binary value */
- INT16S mnem;
-
- /* 4 chars for ending: esc two-char nul */
- while ((c = *(source++)) && (result < (save + n - 4)))
- {
- /* printf(" %c %c %c",c,*source,s_esc); */
- if (c == s_esc)
- {
- /* Two esc in a row -> one escape
- *
- * If esc followed by defined mnemonic, next char is
- * mnemonic.
- */
-
- if (*source == s_esc)
- {
- o = *(s_in + s_esc);
- source++;
- }
- else
- {
- o = findc(*source * C256 + *(source + 1));
- source += 2;
- }
- }
- else
- o = *(s_in + c);
- if (!o)
- o = 64; /* if not defined in input: underline */
-
- /* printf(" %d %d %c",o,r_esc,r_esc); */
- if (*(r_out + o) == r_esc)
- {
- *result++ = r_esc;
- *result++ = r_esc;
- }
- else if (*(r_out + o))
- *result++ = *(r_out + o);
- else
- {
- mnem = *(chset + o);
- *result++ = r_esc;
- *result++ = *(r_out + *(s_in + (mnem / C256)));
- *result++ = *(r_out + *(s_in + (mnem % C256)));
- }
- }
- *result++ = '\0';
- return (save);
- }
- /*
- ** getchset -- fetch the named character set.
- **
- ** First loop through the list of already loaded character sets.
- ** If found, return a pointer to it. Otherwise read the set into
- ** memory and append it to the CHARSET chain.
- **
- ** Parameters:
- ** s -- the name of the character set to get.
- ** esc -- the value for the out-of-band escape character.
- **
- ** Returns:
- ** pointer to character set or NULL on error.
- **
- ** Side Effects:
- ** mallocs memory for character set name and for the
- ** CHARSET structure. Gradually increases size of
- ** running image if many sets are requested.
- */
-
- CHARSET *
- getchset(s, esc)
- char *s;
- INT16S esc;
- {
- register CHARSET *c, *c1;
- register char *p;
-
- /* Up case the character set name. */
- for (p = s; *p; p++)
- *p = upper(*p);
-
- /* Load the character base file into chset. */
- if (getchbas() == 0)
- return (NULL);
-
- /* Loop through the chain of character set names. */
- for (c = charsets; c && strcmp(c->name, s); c = c->next)
- c1 = c;
-
- /*
- * The requested character set wasn't found on the in-memory chain.
- * Load it up from the disk file.
- */
-
- if (!c)
- {
- c = (CHARSET *) xalloc(sizeof (CHARSET));
- c->next = NULL;
- c->out = getoutch(s);
- if (!c->out)
- {
- free(c);
- return (NULL);
- }
- c->name = newstr(s);
- c->in = getinch(s);
- c->esc = esc;
- if (charsets)
- c1->next = c;
- else
- charsets = c;
- }
- return (c);
- }
- /*
- ** findc -- find position of argument character in chset.
- **
- ** Parameters:
- ** c -- ASCII value of two-byte character mnemonic
- **
- ** Returns:
- ** index to c's position in chset or 0 if not found.
- **
- ** Side Effects:
- ** none.
- */
-
- static int
- findc(c)
- register unsigned int c;
- {
- register INT16S *cs;
- register int i;
-
- i = chset[0] + 1;
- cs = &chset[i];
- while (--i > 0 && c != *--cs)
- ;
- /* printf(" %d ",i); */
- return (i); /* zero == not found */
- }
- /*
- ** getchbas -- load character set base definition file
- **
- ** Load the character set base definition file and assign the
- ** global var chset to the beginning of it.
- **
- ** Parameters:
- ** none.
- **
- ** Returns:
- ** 1 if file load successful or previously done, NULL
- ** on error.
- **
- ** Side Effects:
- ** mallocs storage that global chset points at.
- */
-
- static int
- getchbas()
- {
- INT16S sz;
- FILE *f;
- char name[MAXNAME];
-
- if (mapdir && fmnem)
- (void) sprintf(name, "%s/%s", mapdir, fmnem);
- else
- return (NULL);
- if (!chset)
- {
- if ((f = dfopen(name, "r")) == NULL)
- {
- syserr("getchbas: can't open charset def'n file %s", name);
- # ifdef LOG
- syslog(LOG_ALERT, "getchbas: can't open charset def'n file %s: %m", name);
- # endif /* LOG */
- return (NULL);
- }
-
- /* The first short contains the size of the file. */
- if (fread(&sz, sizeof (INT16S), 1, f) != 1)
- {
- syserr("getchbas: error reading size of charset def'n file %s", name);
- # ifdef LOG
- syslog(LOG_ALERT, "getchbas: error reading size of charset def'n file %s: %m", name);
- # endif /* LOG */
- (void) fclose(f);
- return (NULL);
- }
-
- /* Allocate storage for the char set definitions and read it */
- chset = (IN_CH *) xalloc((unsigned) (sz * sizeof (INT16S)));
- rewind(f);
- if (fread(chset, sizeof (INT16S), sz, f) != sz)
- {
- syserr("getchbas: error reading charset def'n file %s", name);
- # ifdef LOG
- syslog(LOG_ALERT, "getchbas: error reading charset def'n file %s: %m", name);
- # endif /* LOG */
- (void) fclose(f);
- return (NULL);
- }
- /* printf("charsz %d chars %22.22s\n",sz*sizeof(INT16S),chset); */
- (void) fclose(f);
- return ((int) sz);
- }
- return (1);
- }
- /*
- ** getinch -- load a character set input translation table.
- **
- ** Parameters:
- ** charset -- the character set to load from.
- **
- ** Returns:
- ** pointer to result or NULL if error
- **
- ** Side Effects:
- ** allocates space for data read from files.
- */
-
- static INT16S *
- getinch(charset)
- const char *charset;
- {
- FILE *f;
- int sz;
- IN_CH *in;
- char name[MAXNAME];
-
- if (mapdir && charset)
- (void) sprintf(name, "%s/%s", mapdir, charset);
- else
- return (NULL);
- if ((f = dfopen(name, "r")) == NULL)
- {
- syserr("getchin: open of charset input translation file %s", name);
- # ifdef LOG
- syslog(LOG_ALERT, "getchin: open of charset input translation file %s: %m", name);
- # endif /* LOG */
- return (NULL);
- }
- sz = C256 * sizeof (IN_CH);
- in = (IN_CH *) xalloc(sz);
- if (fread(in, sizeof (IN_CH), C256, f) != C256)
- {
- syserr("getchin: read of charset input translation file %s", name);
- # ifdef LOG
- syslog(LOG_ALERT, "getchin: read of charset input translation file %s: %m", name);
- # endif /* LOG */
- (void) fclose(f);
- return (NULL);
- }
- (void) fclose(f);
- in[0] = '\0';
- /* printf(" %c %d ",c,in[0]); */
- return (in);
- }
- /*
- ** getoutch -- load a character set output translation table.
- **
- ** Parameters:
- ** charset -- the character set to load from.
- **
- ** Returns:
- ** pointer to result or NULL if error
- **
- ** Side Effects:
- ** allocates space for data read from files.
- */
-
- static CHAR8U *
- getoutch(charset)
- const char *charset;
- {
- FILE *f;
- unsigned sz1;
- OUT_CH *out;
- char name[MAXNAME];
-
- if (mapdir && charset)
- (void) sprintf(name, "%s/%s", mapdir, charset);
- else
- return (NULL);
- if ((f = dfopen(name, "r")) == NULL)
- {
- syserr("getchout: open of charset output translation file %s", name);
- # ifdef LOG
- syslog(LOG_ALERT, "getchout: open of charset output translation file %s: %m", name);
- # endif /* LOG */
- return (NULL);
- }
- sz1 = chset[0];
- (void) fseek(f, C256L * sizeof (INT16S), 0);
- out = (OUT_CH *) xalloc(sz1 * sizeof (OUT_CH));
- if (fread(out, sizeof (OUT_CH), sz1, f) != sz1)
- {
- syserr("getchout: read of charset output translation file %s", name);
- # ifdef LOG
- syslog(LOG_ALERT, "getchout: read of charset output translation file %s: %m", name);
- # endif /* LOG */
- (void) fclose(f);
- return (NULL);
- }
- (void) fclose(f);
- out[0] = '\0';
- return (out);
- }
- /*
- ** UPPER -- turn letter into upper case.
- **
- ** Parameters:
- ** c -- character to turn into upper case.
- **
- ** Returns:
- ** c, in upper case.
- **
- ** Side Effects:
- ** none.
- */
-
- static char
- upper(c)
- register char c;
- {
- return (isascii(c) && islower(c) ? toupper(c) : c);
- }
- #endif /* BIT8 */
-